package com.wyl.auth.aspect;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.wyl.auth.config.security.SecurityHolder;
import com.wyl.auth.config.security.SecurityUser;
import com.wyl.auth.entity.SysMenu;
import com.wyl.auth.entity.UserOperationLog;
import com.wyl.auth.util.IpUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
 * @Description
 * @Author WuYiLong
 * @Date 2025/4/16 20:46
 */
@Component
@Aspect
public class UserOperationLogAspect {

    private static final Logger log = LoggerFactory.getLogger(UserOperationLogAspect.class);

    @Pointcut("@annotation(io.swagger.annotations.ApiOperation)")
    public void targetMethod() {
    }

    @Around(value = "targetMethod()")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        SecurityUser securityUser = SecurityHolder.getUser();
        if(securityUser == null) {
            return joinPoint.proceed();
        }
        UserOperationLog sysLog = new UserOperationLog();
        sysLog.setUserId(securityUser.getUserId());
        sysLog.setCreateTime(LocalDateTime.now());
        sysLog.setUsername(securityUser.getUsername());

        List<String> pathNames = new ArrayList<>();
        List<String> paths = new ArrayList<>();
        Signature signature = joinPoint.getSignature();
        String name = signature.getName();
        Class controller = signature.getDeclaringType();
        Annotation[] annotations = controller.getAnnotations();
        for (Annotation annotation : annotations) {
            if(annotation instanceof Api) {
                Api api = (Api) controller.getAnnotation(Api.class);
                if (api.tags().length > 0) {
                    pathNames.add(StrUtil.join("/", api.tags()));
                }
            }else if(annotation instanceof RequestMapping) {
                RequestMapping requestMapping = (RequestMapping)controller.getAnnotation(RequestMapping.class);
                String[] value = requestMapping.value();
                List<String> objects = new ArrayList<>();
                for (String s : value) {
                    String s1 = s.replaceAll("/", "");
                    objects.add(s1);
                }
                paths.add(StrUtil.join("/",objects));
            }
        }

        Method[] methods = controller.getMethods();
        for (Method method : methods) {
            if(name.equals(method.getName())) {
                ApiOperation apiOperation = method.getAnnotation(ApiOperation.class);
                pathNames.add(apiOperation.value());

                // 获取请求路径
                Annotation[] methodAnnotations = method.getAnnotations();
                for (Annotation annotation : methodAnnotations) {
                    ArrayList<String> pathList = new ArrayList<>();
                    if(annotation instanceof PostMapping) {
                        PostMapping postMapping = (PostMapping) annotation;
                        String[] value = postMapping.value();
                        pathList.addAll(Arrays.asList(value));
                    }else if(annotation instanceof GetMapping) {
                        GetMapping getMapping = (GetMapping) annotation;
                        String[] value = getMapping.value();
                        pathList.addAll(Arrays.asList(value));
                    }else if(annotation instanceof DeleteMapping) {
                        DeleteMapping deleteMapping = (DeleteMapping) annotation;
                        String[] value = deleteMapping.value();
                        pathList.addAll(Arrays.asList(value));
                    }else if(annotation instanceof PutMapping) {
                        PutMapping putMapping = (PutMapping) annotation;
                        String[] value = putMapping.value();
                        pathList.addAll(Arrays.asList(value));
                    }else if(annotation instanceof RequestMapping) {
                        RequestMapping requestMapping = (RequestMapping)annotation;
                        String[] value = requestMapping.value();
                        pathList.addAll(Arrays.asList(value));
                    }
                    List<String> objects = new ArrayList<>();
                    if(CollUtil.isNotEmpty(pathList)) {
                        for (String s : pathList) {
                            String s1 = s.replaceAll("/", "");
                            objects.add(s1);
                        }
                        paths.add(StrUtil.join("/",objects));
                    }

                }
            }
        }

        if(CollUtil.isNotEmpty(pathNames)) {
            sysLog.setRequestPathName(StrUtil.join("/",pathNames));
        }

        if(CollUtil.isNotEmpty(paths)) {
            sysLog.setRequestPath(StrUtil.join("/",paths));
        }

        // 获取ip地址
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
        String ipAddress = IpUtils.getClientIp(request);
        if(ipAddress == null) {
            ipAddress = request.getRemoteAddr();
        }
        sysLog.setIpAddress(ipAddress);
        long starTime = System.currentTimeMillis();
        Object proceed = joinPoint.proceed();
        long endTime = System.currentTimeMillis();
        sysLog.setTimeCost(endTime - starTime);
        sysLog.insert();
        return proceed;
    }
}